#include<cstdlib>
#include<iostream>
#include<mysql/mysql.h>                                                                                                                                    
#include<jsoncpp/json/json.h>
#include<string> 
#include<mutex>
using namespace std;

#define HOST "192.168.35.143"
#define USER "root"
#define PASS ""
#define NAME "OrderSystem"

MYSQL* DishMysqlInit(){ 
  //初始化
  MYSQL* mysql = mysql_init(NULL);
  if(mysql == NULL){
    cout << "init mysql handler failed!\n";
    return NULL;
  }
  //连接服务器
  if(mysql_real_connect(mysql, HOST, USER, PASS, NAME, 0 ,NULL, 0) == NULL){
    printf("connect mysql server failed:%s\n", mysql_error(mysql));
    mysql_close(mysql);
    return NULL;
  }
  //设置字符集
  if(mysql_set_character_set(mysql,"utf8") != 0){
    cout << "set mysql character failed:" << mysql_error(mysql) << endl;
    mysql_close(mysql);
    return NULL;
  }
  return mysql;
}

void DishMysqlDestory(MYSQL* mysql){
  if(mysql != NULL)
    mysql_close(mysql);
}

//sql执行函数
bool DishMysqlQuery(MYSQL* mysql, const string& sql){
  if(mysql_query(mysql,sql.c_str()) != 0){
    cout << sql << endl;
    cout << "query falied:" << mysql_error(mysql) << endl;
    return false;
  }
  return true;
}

class TableDish{
  public:
    //初始化数据库操作句柄
    TableDish()
      :_mysql(NULL)
    {
      _mysql = DishMysqlInit();   
      if(_mysql == NULL)
        exit(-1);
    } 

    //释放销毁数据库操作句柄
    ~TableDish(){
      DishMysqlDestory(_mysql);
    }

    //插入新增菜品信息
    bool DishInsert(const Json::Value& dish){
      //insert Dish values("null,红烧肉，1800, "红色的肉", now());
      //校验
      if(Check(dish) == false)
        return false; 
#define INSERT_DISH "insert Dish values(null, '%s', %d, '%s', now());"  
      char sql[4096] = {0};
      sprintf(sql,INSERT_DISH,dish["name"].asCString(),dish["price"].asInt(), dish["info"].asCString());
      return DishMysqlQuery(_mysql,sql);
    }

    //将dish_id对应的菜品信息修改为新的dish菜品信息
    bool DishUpdate(int dish_id, const Json::Value& dish){
      //"update Dish set name = '%s', price='%d', info='%s' where id='%d'";
      //校验
      if(Check(dish) == false)
        return false;
      else if(dish_id <= 0){
        cout << "not this id" << endl;
        return false;
      }
#define UPDATE_DISH "update Dish set name='%s', price=%d, info='%s' where id=%d;"
      char sql[4096] = { 0 };    
      sprintf(sql,UPDATE_DISH,dish["name"].asCString(), dish["price"].asInt(), dish["info"].asCString(), dish_id);
      return DishMysqlQuery(_mysql,sql);
    }

    //删除dish_id对应的菜品信息
    bool DishDelete(int dish_id){
      if(dish_id <= 0){
        cout << "not this id" << endl;
        return false;
      }
      //delete from Dish where id='%d';
#define DELETE_DISH "delete from Dish where id = %d;"
      char sql[4096] = { 0 };
      sprintf(sql, DELETE_DISH, dish_id);
      return DishMysqlQuery(_mysql,sql);
    }   

   //返回所有菜品信息
    bool DishGetAll(Json::Value* dishes){
    //"select * from Dish;"
#define SELECT_ALL_DISH "select * from Dish;"
      char sql[4096] = { 0 };
      sprintf(sql, SELECT_ALL_DISH);
      //线程安全
      _mutex.lock();
      bool ret = DishMysqlQuery(_mysql,sql);
      if(ret == false){
        _mutex.unlock();
        return false;//不需要关闭mysql接口，外界会关闭
      } 
      MYSQL_RES* res = mysql_store_result(_mysql);
      if(res == NULL){
        cout << "store result failed:" << mysql_error(_mysql) << endl;
        _mutex.unlock();
        return false;
      }
      _mutex.unlock();

      int new_row = mysql_num_rows(res);
      if(new_row < 1){
        cout << "no dish" << endl;
        return false;
      }
      int new_col = mysql_num_fields(res);
      for(int i = 0; i < new_row; i++){
        MYSQL_ROW row = mysql_fetch_row(res);
        Json::Value dish;
        dish["id"] = atoi(row[0]);
        dish["name"] = row[1];
        dish["price"] = atoi(row[2]);
        dish["info"] = row[3];
        dish["ctime"] = row[4];
        dishes->append(dish);//将单个菜品信息作为数组元素添加到输出参数dishes中
      }
      mysql_free_result(res);
      return true;
    }
    
    //获取指定菜品信息（依据dish_id)
    bool DishGetOne(int dish_id, Json::Value* dish){
      if(dish_id <= 0)
        return false;
      //"select name,price,info,ctime from Dish where id='%d';"
#define GET_ONE_DISH "select name,price,info,ctime from Dish where id=%d;"
      char sql[4096] = { 0 };
      sprintf(sql, GET_ONE_DISH, dish_id);
      //线程安全
      _mutex.lock();
      bool ret = DishMysqlQuery(_mysql, sql); 
      if(ret == false){
        _mutex.unlock();
        return false;
      }

      MYSQL_RES* res = mysql_store_result(_mysql);
      if(res == NULL){
        cout << "store result failed:" << mysql_error(_mysql) << endl;
        _mutex.unlock();
          return false;
        }
        _mutex.unlock();

        int num_row = mysql_num_rows(res);
        //只有一行数据---row应该为1
        if(num_row < 1){
          cout << "have no this dish :" << dish_id << endl;
          return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        (*dish)["id"] = dish_id ;
        (*dish)["name"] = row[0];
        (*dish)["price"] = atoi(row[1]);
        (*dish)["info"] = row[2];
        (*dish)["ctime"] = row[3];
        mysql_free_result(res);
        return true;
      }

    private:
      bool Check(const Json::Value& dish){
      //insert Dish values("null,红烧肉，1800, "红色的肉", now());
      //校验(不存在-未赋值，或值不符合实际)
      if(dish["name"].empty() == true || dish["name"].asString().size() == 0){
        cout << "new dish name is not exists!" << endl;
        return false;
      }
      if(dish["price"].empty() == true || dish["price"].asInt() <= 0){
        cout << "new id price is error!" << endl;
        return false;
      }
      if(dish["info"].empty() == true || dish["info"].asString().size() == 0){
        cout  << "new dish info is null" << endl;
        return false;
      }
      return true;
    }
  private:
    MYSQL* _mysql;
    mutex _mutex;
};

